home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1995
/
MacHack 1995.toast
/
Presentations
/
Presentations ’91
/
MPW Stand-Alone Libraries
/
UMultiSegSA.incl.p
< prev
next >
Wrap
Text File
|
1991-03-02
|
30KB
|
1,108 lines
{ A useful type definitions for routines that manipulate }
{ the main jumptable and gather information about segments. }
TYPE
IntArray = ARRAY [0..maxInt] OF Integer;
IArrPtr = ^IntArray;
IArrHdl = ^IArrPtr;
SegmentInfo = RECORD
firstProc: Integer; { offset of first proc in main jump table }
numJTProcs: Integer; { number of procs in the main jump table }
END;
{--------------------------------------------------------------------------------------------------}
{$S TInit}
PROCEDURE TMultiSegSA.IMultiSegSA(aFile: FileSpec;
mainType: ResType;
mainID: Integer;
mainName: StringHandle;
otherType: ResType);
VAR
aStrHdl: StringHandle;
BEGIN
fSrcRefNum := 0;
fDestRefNum := 0;
fFileSpec := aFile;
fMainType := mainType;
fMainID := mainID;
fOtherType := otherType;
IF (mainName <> NIL) THEN
BEGIN
aStrHdl := mainName;
FailOSErr(HandToHand(Handle(aStrHdl)));
fMainName := aStrHdl;
END
ELSE
fMainName := NIL;
{ These must be initialzed to their "empty" table sizes or havoc will ensue }
fJTSize := 4;
fCtorJTSize := 4;
fDtorJTSize := 4;
fSegTabSize := 4;
{ Standalone code size is the above plus size of BSR, and multiseg type }
fSACodeSize := 8 + fJTSize + fCtorJTSize + fDtorJTSize + fSegTabSize;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
{ Attempt to open the source resource fork and create the destination resource }
{ fork. Delete the destination resource fork if it exists prior to attempting }
{ to create it. }
PROCEDURE TMultiSegSA.OpenFiles;
VAR
tempName: Str255;
fi: FailInfo;
err: OSErr;
PROCEDURE HdlFailure(error: Integer; message: LongInt);
BEGIN
IF (fSrcRefNum <> 0) AND (fSrcRefNum <> -1) THEN CloseResFile(fSrcRefNum);
IF (fDestRefNum <> 0) AND (fDestRefNum <> -1) THEN CloseResFile(fDestRefNum);
tempName := concat('An error occured while opening the file ',tempName);
gMakeSA.Stop(tempName);
END;
BEGIN
CatchFailures(fi, HdlFailure);
tempName := fFileSpec.fileName^^;
tempName := concat(tempName, kSASuffix);
fDestRefNum := OpenResFile(tempName); { open destination file }
IF (fDestRefNum = -1) OR (fDestRefNum = 0) THEN
BEGIN
err := ResError;
IF (err = resFNotFound) OR (err = fnfErr) THEN
BEGIN
CreateResFile(tempName); { create destination file }
FailResError;
fDestRefNum := OpenResFile(tempName);
FailResError;
END
ELSE
FailResError;
END;
tempName := fFileSpec.fileName^^;
fSrcRefNum := OpenResFile(tempName); { open source file }
IF (fSrcRefNum = -1) OR (fSrcRefNum = 0) THEN FailResError;
Success(fi);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.CloseSourceFile;
BEGIN
CloseResFile(fSrcRefNum); { We're done with the source file }
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.CloseDestinationFile;
BEGIN
CloseResFile(fDestRefNum); { We're done with the destination file }
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.ShowNumericalProgress(aStr: Str255; aLong: LongInt);
VAR
tempStr: Str255;
BEGIN
NumToString(aLong, tempStr);
tempStr := Concat(aStr, tempStr);
gMakeSA.DoShowProgress(tempStr);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.ShowTextProgress(aStr: Str255);
BEGIN
gMakeSA.DoShowProgress(aStr);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.ReplaceSegment(theRsrc: Handle; theType: ResType; theID: Integer; VAR theName: Str255);
VAR
tempHdl: Handle;
tempAttrs: Integer;
BEGIN
SetResLoad(FALSE); { if the rsrc exists, dispose of it }
tempHdl := NIL;
tempHdl := Get1Resource(theType, theID);
IF (tempHdl <> NIL) THEN
BEGIN
tempAttrs := GetResAttrs(tempHdl);
tempAttrs := BAND(tempAttrs, $FFF7);
SetResAttrs(tempHdl, tempAttrs); { Turn off the protect bit }
RmveResource(tempHdl);
FailResError;
DisposHandle(tempHdl);
END;
SetResLoad(TRUE);
AddResource(theRsrc, theType, theID, theName);
FailResError;
WriteResource(theRsrc);
FailResError;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.AddMainSegment(VAR saCode: Handle);
VAR
fi: FailInfo;
tempName: Str255;
PROCEDURE HdlAddFailure(error: Integer; message: LongInt);
BEGIN
SetResLoad(TRUE);
IF (saCode <> NIL) THEN DisposHandle(saCode);
UseResFile(fSrcRefNum); { reset to our src rsrc file }
CloseResFile(fDestRefNum);
END;
PROCEDURE HdlUpdateFailure(error: Integer; message: LongInt);
BEGIN
IF (saCode <> NIL) THEN ReleaseResource(saCode);
UseResFile(fSrcRefNum); { reset to our src rsrc file }
CloseResFile(fDestRefNum);
END;
BEGIN
CatchFailures(fi, HdlAddFailure);
UseResFile(fDestRefNum); { set to our dest rsrc file before adding resource }
IF (fMainName <> NIL) THEN
tempName := fMainName^^
ELSE
tempName := '';
ReplaceSegment(saCode, fMainType, fMainID, tempName);
Success(fi);
CatchFailures(fi, HdlUpdateFailure);
UpdateResFile(fDestRefNum);
FailResError;
ReleaseResource(saCode);
UseResFile(fSrcRefNum); { reset to our src rsrc file }
Success(fi);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.AddOtherCodeSegments(saCode: Handle; otherSegType: ResType);
TYPE
SACodeType = (sepSeg, mainSeg, jtSeg, ctordtorSeg);
CodeDesc = RECORD
codeID: Integer;
codeName: Str255;
codeSize: LongInt;
rsrcType: ResType;
codeType: SACodeType;
END;
VAR
theCode: Handle;
i, newID: Integer;
theCount: Integer;
fi: FailInfo;
codeArray: TDynamicArray;
aCodeDesc: CodeDesc;
segInfo: SegmentInfo;
FUNCTION ForThisItemDo(index: ArrayIndex): BOOLEAN;
VAR
aCodeDesc: CodeDesc;
BEGIN
codeArray.GetElementsAt(index, @aCodeDesc, 1);
ShowNumericalProgress('CodeID ', aCodeDesc.codeID);
ShowNumericalProgress('Index ', index);
ForThisItemDo := FALSE;
END;
PROCEDURE AddCodeInfo(VAR aCodeDesc: CodeDesc; aCodeArray: TDynamicArray);
VAR
lower, upper, k: ArrayIndex;
arraySize: ArrayIndex;
temp: CodeDesc;
BEGIN
lower := 1;
arraySize := aCodeArray.GetSize;
upper := arraySize;
REPEAT
k := (lower + upper) DIV 2;
aCodeArray.GetElementsAt(k, @temp, 1);
IF (aCodeDesc.codeID < temp.codeID) THEN
upper := k - 1
ELSE
lower := k + 1;
UNTIL ((aCodeDesc.codeID = temp.codeID) OR (lower > upper));
IF (aCodeDesc.codeID = temp.CodeID) THEN
aCodeArray.InsertElementsBefore(k, @aCodeDesc, 1)
ELSE
aCodeArray.InsertElementsBefore(arraySize + 1, @aCodeDesc, 1);
END;
PROCEDURE CollateCodeInfo(count: Integer; aCodeArray: TDynamicArray);
VAR
aCodeDesc: CodeDesc;
theCode: Handle;
dummy: ArrayIndex;
theID: Integer;
theType: ResType;
theName: Str255;
i: Integer;
BEGIN
SetResLoad(FALSE);
{ Collect code resources info, and sort by ID }
FOR i := 1 TO count DO
BEGIN
theCode := NIL;
theCode := Get1IndResource('CODE', i);
FailNilResource(theCode);
GetResInfo(theCode, theID, theType, theName);
FailResError;
WITH aCodeDesc DO
BEGIN
codeID := theID;
codeName := theName;
codeSize := SizeResource(theCode);
rsrcType := theType;
IF (theID = 0) THEN
codeType := jtSeg
ELSE IF (theName = kCtorDtorSeg) THEN
codeType := ctordtorSeg
ELSE IF (WillBeMerged(theID, theName)) THEN
codeType := mainSeg
ELSE
codeType := sepSeg;
END;
ReleaseResource(theCode);
AddCodeInfo(aCodeDesc, aCodeArray);
END;
{•} dummy := aCodeArray.EachElementDoTil(ForThisItemDo, kIterateForward);
SetResLoad(TRUE);
END;
PROCEDURE HdlAddFailure(error: Integer; message: LongInt);
BEGIN
{ Free the code segment }
IF (theCode <> NIL) THEN DisposHandle(theCode);
SetResLoad(TRUE); { CollateCodeInfo turns it off }
UpdateResFile(fDestRefNum); { force the rsrc map to be updated }
UseResFile(fSrcRefNum); { reset to our src rsrc file }
codeArray.Free; { free the code elements }
END;
BEGIN
theCount := Count1Resources('CODE');
IF (theCount <= 0) THEN Failure(resNotFound, 0);
New(codeArray);
FailNil(codeArray);
codeArray.IDynamicArray(theCount, SizeOf(CodeDesc));
CatchFailures(fi, HdlAddFailure);
CollateCodeInfo(theCount, codeArray);
{ Move the non-main code resources into the new file }
{ Make sure we start at ID = 1. The main entry point }
{ must be in ID = 0. }
newID := 1;
FOR i := 1 TO theCount DO
BEGIN
codeArray.GetElementsAt(i, @aCodeDesc, 1);
theCode := NIL;
theCode := Get1Resource('CODE', aCodeDesc.codeID);
FailNilResource(theCode);
{ Have we found a code segment to be added as a seperate segment, maybe }
IF (aCodeDesc.codeType = sepSeg) THEN
BEGIN
ShowNumericalProgress('Adding segment ', aCodeDesc.codeID);
{ rsrc mgr will think it belongs elsewhere if not detached }
DetachResource(theCode);
UseResFile(fDestRefNum);
ReplaceSegment(theCode, otherSegType, newID, aCodeDesc.codeName);
UseResFile(fSrcRefNum);
{ Get segment info and then modify it's SA jumptable entry }
BlockMove(theCode^, @segInfo, SizeOf(SegmentInfo));
AdjustMainJTable(saCode, 0, aCodeDesc.codeID, newID, segInfo.firstProc, segInfo.numJTProcs);
ShowNumericalProgress('Added segment as ', newID);
newID := newID + 1;
END;
ReleaseResource(theCode);
END;
UpdateResFile(fDestRefNum); { force the rsrc map to be updated }
codeArray.Free; { Release the storage for the array }
Success(fi);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.CalcJTSize(rawJTSize: LongInt);
VAR
tempLong: LongInt;
BEGIN
IF (rawJTSize = 0) THEN
tempLong := 4
ELSE
tempLong := 4 + ((rawJTSize - kCode0Hdr) DIV kJTDivisor);
ShowNumericalProgress('Main jumptable size = ', tempLong);
fJTSize := tempLong;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.CalcCtorJTSize(theSize: LongInt);
VAR
tempLong: LongInt;
BEGIN
IF (theSize = 0) THEN
tempLong := 4
ELSE
tempLong := 4 + ((theSize - kCodeHdr) DIV 2);
ShowNumericalProgress('Ctor jumptable size = ', tempLong);
fCtorJTSize := tempLong;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.CalcDtorJTSize(theSize: LongInt);
VAR
tempLong: LongInt;
BEGIN
IF (theSize = 0) THEN
tempLong := 4
ELSE
tempLong := 4 + ((theSize - kCodeHdr) DIV 2);
ShowNumericalProgress('Dtor jumptable size = ', tempLong);
fDtorJTSize := tempLong;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.CalcSegTableSize(theCount: Integer; hasCtorDtorJT: Boolean);
VAR
tempSize: LongInt;
BEGIN
IF hasCtorDtorJT THEN { if there is a static ctor/dtor jtable then }
tempSize := theCount - 2 { don't include it & code 0 it in our SegTable }
ELSE
tempSize := theCount - 1; { otherwise leave out only code 0 }
IF (theCount <= 0) THEN
tempSize := 4
ELSE
tempSize := 4 + (tempSize * 4);
ShowNumericalProgress('Segment table size = ', tempSize);
fSegTabSize := tempSize;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetNumJTEntries: LongInt;
VAR
tempLong: LongInt;
BEGIN
tempLong := (GetJTSize - 4) DIV 4;
ShowNumericalProgress('Number of main jumptable entries = ', tempLong);
GetNumJTEntries := tempLong;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetNumCtorJTEntries: LongInt;
VAR
tempLong: LongInt;
BEGIN
tempLong := (GetCtorJTSize - 4) DIV 2;
ShowNumericalProgress('Number of static ctor jumptable entries = ', tempLong);
GetNumCtorJTEntries := tempLong;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetNumDtorJTEntries: LongInt;
VAR
tempLong: LongInt;
BEGIN
tempLong := (GetDtorJTSize - 4) DIV 2;
ShowNumericalProgress('Number of static dtor jumptable entries = ', tempLong);
GetNumDtorJTEntries := tempLong;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetNumSegTableEntries: LongInt;
VAR
tempLong: LongInt;
BEGIN
tempLong := (GetSegTableSize - 4) DIV 4;
ShowNumericalProgress('Number of segment table entries = ', tempLong);
GetNumSegTableEntries := tempLong;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetJTSize: LongInt;
BEGIN
GetJTSize := fJTSize;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetCtorJTSize: LongInt;
BEGIN
GetCtorJTSize := fCtorJTSize;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetDtorJTSize: LongInt;
BEGIN
GetDtorJTSize := fDtorJTSize;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetSegTableSize: LongInt;
BEGIN
GetSegTableSize := fSegTabSize;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetSACodeSize: LongInt;
BEGIN
GetSACodeSize := fSACodeSize;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
{ We're only concerned with CODE 1 here. All other normal code segments }
{ will not be merged into the standalone code resources. Thus they are "filtered out" }
{ by this method. This method must be overridden if you need to change which }
{ code segments are merged into the final standalone CODE segment. }
FUNCTION TMultiSegSA.WillBeMerged(theID: Integer; theName: Str255): BOOLEAN;
BEGIN
IF (theID = 1) THEN { We are only concerned with CODE 1 }
WillBeMerged := TRUE
ELSE
WillBeMerged := FALSE;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.CalcSACodeSize;
VAR
theCode: Handle;
i: Integer;
theCount: Integer;
theID: Integer;
theType: ResType;
theName: Str255;
theSize: LongInt;
fi: FailInfo;
hasCtorDtorJT: Boolean;
PROCEDURE HdlFailure(error: Integer; message: LongInt);
VAR
tempName: Str255;
tempLong: LongInt;
BEGIN
tempName := fFileSpec.fileName^^;
CASE error OF
resNotFound:
WriteLn(kErrorMarker, tempName, ' does not contain CODE resources.');
OTHERWISE
WriteLn(kErrorMarker, tempName, ' error occured while scanning CODE resources.');
END;
END;
BEGIN
CatchFailures(fi, HdlFailure);
SetResLoad(FALSE); { We only want info on the rsrc's. DONT LOAD THEM! }
{ The first thing in the SACode is the BSR instruction. }
fSACodeSize := kBSRSize;
{ Now add in the size of the segment's resource type }
fSACodeSize := fSACodeSize + kSegTypeSize;
theCount := Count1Resources('CODE');
IF (theCount <= 0) THEN Failure(resNotFound, 0);
hasCtorDtorJT := FALSE; { assume there are no static ctor and dtors }
{ Sum the CODE segment sizes. However, watch out for special segments, and }
{ don't add the sizes of anything other than code 0 and code 1 }
FOR i := 1 TO theCount DO
BEGIN
theCode := NIL;
theCode := Get1IndResource('CODE', i);
FailNilResource(theCode);
theSize := SizeResource(theCode);
GetResInfo(theCode, theID, theType, theName);
ReleaseResource(theCode);
IF (theID = 0) THEN { Found jump table }
BEGIN
CalcJTSize(theSize);
END
ELSE IF (theName = kCtorDtorSeg) THEN { Found CtorDtor jump table }
BEGIN
CalcCtorJTSize(theSize);
CalcDtorJTSize(theSize);
hasCtorDtorJT := TRUE;
END
ELSE IF WillBeMerged(theID, theName) THEN { Found a code segment we'll merge }
fSACodeSize := fSACodeSize + theSize - kCodeHdr;
END;
CalcSegTableSize(theCount, hasCtorDtorJT);
theSize := fSACodeSize + GetJTSize + GetCtorJTSize + GetDtorJTSize + GetSegTableSize;
ShowNumericalProgress('Estimated standalone size = ', theSize);
IF (theSize > maxInt) THEN
gMakeSA.Stop('Main code segement exceeds 32K');
fSACodeSize := theSize;
SetResLoad(TRUE);
Success(fi);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.AllocateSACode(theSize: LongInt): Handle;
VAR
aHandle: Handle;
BEGIN
aHandle := NIL;
aHandle := NewHandle(theSize);
FailNIL(aHandle);
AllocateSACode := aHandle;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetCode0: Handle;
VAR
aHandle: Handle;
BEGIN
aHandle := NIL;
aHandle := Get1Resource('CODE', 0);
FailNilResource(aHandle);
GetCode0 := aHandle;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
FUNCTION TMultiSegSA.GetCtorDtorJT: Handle;
VAR
aHandle: Handle;
BEGIN
aHandle := NIL;
aHandle := Get1NamedResource('CODE', kCtorDtorSeg);
{ *** This can fail because not every piece of code has *** }
{ *** a CtorDtor jumptable. Thus we can't call FailNil! *** }
IF (ResError <> noErr) THEN
aHandle := NIL;
GetCtorDtorJT := aHandle;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.BuildBSR(code0, saCode: Handle; VAR saPos: LongInt);
VAR
theBSRinst: LongInt; { The full BSR $XXXX instruction goes here }
theEntryPt: Integer; { 1st entry in original main jumptable has offset to MAIN }
theOffset: Integer; { Our calculated offset to main entry point }
BEGIN
{ offset to main entry point of SARuntime is 1st entry in main jumptable }
BlockMove(Ptr(ORD(code0^)+kCode0Hdr), @theEntryPt, 2);
{ move the BSR instruction into the standalone and set it to BSR to MAIN }
theBSRinst := BSL(kBSRCode, 16);
theOffset := kSegTypeSize + GetJTSize + GetCtorJTSize + GetDtorJTSize + GetSegTableSize;
theOffset := theOffset + theEntryPt + 2;
theBSRinst := theBSRinst + theOffset;
BlockMove(@theBSRinst, Ptr(ORD(saCode^)+saPos), kBSRSize);
saPos := saPos + kBSRSize;
ShowNumericalProgress('BSR offset to main proc is: ', theOffset);
ShowNumericalProgress('BSR to main proc ends at: ', saPos);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.BuildSegType(segType: ResType; saCode: Handle; VAR saPos: LongInt);
BEGIN
{ move the BSR instruction into the standalone and set it to BSR to MAIN }
BlockMove(@segType, Ptr(ORD(saCode^)+saPos), kSegTypeSize);
ShowNumericalProgress('Offset to segment restype is: ', saPos);
saPos := saPos + kSegTypeSize;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.BuildJumpTable(code0, saCode: Handle; VAR saPos: LongInt);
TYPE
JTEntry = RECORD
offset: Integer;
move: Integer;
segNum: Integer;
loadSeg: Integer;
END;
VAR
numJTEntries: LongInt;
code0Pos: LongInt;
theEntry: JTEntry;
i: Integer;
BEGIN
{ move the numJTEntries into the standalone }
numJTEntries := GetNumJTEntries;
BlockMove(@numJTEntries, Ptr(ORD(saCode^)+saPos), kNumJTSize);
saPos := saPos + kNumJTSize;
code0Pos := kCode0Hdr;
FOR i := 0 TO numJTEntries-1 DO
BEGIN
BlockMove(Ptr(ORD(code0^)+code0Pos), @theEntry, SizeOf(JTEntry));
BlockMove(@theEntry.offset, Ptr(ORD(saCode^)+saPos), 2);
BlockMove(@theEntry.segNum, Ptr(ORD(saCode^)+saPos+2), 2);
code0Pos := code0Pos + SizeOf(JTEntry);
saPos := saPos + 4;
END;
ShowNumericalProgress('Main jump table ends at: ', saPos);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.BuildCtorJTable(theJT, saCode: Handle; VAR saPos: LongInt);
VAR
saveSAPos: LongInt;
theJTPos: LongInt;
numEntries: LongInt; { number of Ctor JT entries we actually find }
count: Integer; { number of Ctor JT entries we think there are }
theEntry: Integer;
i: Integer;
BEGIN
saveSAPos := saPos; { remember this for when we stuff # JT entries }
count := GetNumCtorJTEntries; { This was determined earlier }
numEntries := 0; { we'll assume that there are null entries }
theJTPos := kCodeHdr; { skip over code header }
saPos := saPos + kNumJTSize; { leave room at top for num of JT entries }
IF (theJT = NIL) THEN { Whoops! Handle this as best we can... }
count := 0;
{ Remember that ctor entries are every other _even_ word offset after code header }
FOR i := 0 TO count-1 DO
BEGIN
BlockMove(Ptr(ORD(theJT^)+theJTPos), @theEntry, 2);
IF (theEntry <> 0) THEN { skip over null entry }
BEGIN
BlockMove(@theEntry, Ptr(ORD(saCode^)+saPos), 2);
saPos := saPos + ((i + 1) * 2); { bump offset up one word }
numEntries := numEntries + 1;
END;
theJTPos := theJTPos + ((i + 1) * 2); { bump offset up one word }
END;
{ Now move in the number of JT entries at top of table }
BlockMove(@numEntries, Ptr(ORD(saCode^)+saveSAPos), kNumJTSize);
ShowNumericalProgress('Ctor table ends at: ', saPos);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.BuildDtorJTable(theJT, saCode: Handle; VAR saPos: LongInt);
VAR
saveSAPos: LongInt;
theJTPos: LongInt;
numEntries: LongInt; { number of Dtor JT entries we actually find }
count: Integer; { number of Dtor JT entries we think there are }
theEntry: Integer;
i: Integer;
BEGIN
saveSAPos := saPos; { remember this for when we stuff # JT entries }
count := GetNumDtorJTEntries; { This was determined earlier }
{ skip all the way to last Dtor entry. }
{ Remember that dtor entries are every other _odd_ word offset after code header }
theJTPos := kCodeHdr + ((count-1) * 2) + 2;
numEntries := 0; { we'll assume that there are null entries }
saPos := saPos + kNumJTSize; { leave room at top for num of JT entries }
IF (theJT = NIL) THEN { Whoops! Handle this as best we can... }
count := 0;
FOR i := count-1 DOWNTO 0 DO
BEGIN
BlockMove(Ptr(ORD(theJT^)+theJTPos), @theEntry, 2);
IF (theEntry <> 0) THEN { skip over null entry }
BEGIN
BlockMove(@theEntry, Ptr(ORD(saCode^)+saPos), 2);
saPos := saPos + ((i + 1) * 2); { bump offset down one word }
numEntries := numEntries + 1;
END;
theJTPos := theJTPos - ((i + 1) * 2); { bump offset down one word }
END;
{ Now move in the number of JT entries at top of table }
BlockMove(@numEntries, Ptr(ORD(saCode^)+saveSAPos), kNumJTSize);
ShowNumericalProgress('Dtor table ends at: ', saPos);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.BuildSegTable(saCode: Handle; VAR saPos: LongInt);
TYPE
LongArray = ARRAY [0..maxInt] OF LongInt;
LArrPtr = ^LongArray;
LArrHdl = ^LArrPtr;
VAR
i: Integer;
count: Integer;
laPtr: LArrPtr;
numEntries: LongInt;
laOffset: LongInt;
BEGIN
count := GetNumSegTableEntries;
numEntries := count;
laOffset := saPos;
BlockMove(@numEntries, Ptr(ORD(saCode^)+laOffset), kNumJTSize);
laOffset := laOffset + kNumJTSize;
HLock(saCode);
laPtr := LArrHdl(saCode)^;
laPtr := LArrPtr(ORD(laPtr) + laOffset);
FOR i := 0 TO count-1 DO
laPtr^[i] := 0;
saPos := saPos + GetSegTableSize;
HUnlock(saCode);
ShowNumericalProgress('Segment table ends at: ', saPos);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.AdjustMainJTable(saCode: Handle;
segOffset: LongInt;
oldSegNum, newSegNum, jtOffset, numEntries: Integer);
VAR
i: Integer;
iaPtr: IArrPtr;
jtEntry: Integer;
segEntry: Integer;
nextOffset: Integer;
myJTOffset: Integer;
fi: FailInfo;
PROCEDURE HdlFailure(error: Integer; message: LongInt);
VAR
shortStr: Str15;
tempStr: Str255;
BEGIN
IF (saCode <> NIL) THEN HUnlock(saCode);
NumToString(error, tempStr);
shortStr := tempStr;
NumToString(message, tempStr);
tempStr := concat('Original segment was ', shortStr, ' whereas segment being merged is ', tempStr);
WriteLn(Diagnostic,
'Segment number mismatch occured while adjusting main jump table.');
WriteLn(Diagnostic, tempStr);
END;
BEGIN
CatchFailures(fi, HdlFailure);
HLock(saCode);
myJTOffset := jtOffset DIV 4; { original jumptable entry is 8 bytes, divide by 4 }
iaPtr := IArrHdl(saCode)^;
iaPtr := IArrPtr(ORD(iaPtr) + kJTStart); { point to beginning of SA jumptable }
FOR i := 0 TO numEntries-1 DO
BEGIN
nextOffset := myJTOffset + (i * 2);
jtEntry := iaPtr^[nextOffset];
segEntry := iaPtr^[nextOffset+1];
IF (segEntry <> oldSegNum) THEN
Failure(segEntry, oldSegNum);
iaPtr^[nextOffset] := jtEntry + segOffset;
iaPtr^[nextOffset+1] := newSegNum; { Set the segment number to the new value }
END;
HUnlock(saCode);
Success(fi);
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.Merge1Segment(segNum: Integer; theCode: Handle; codeSize: LongInt;
saCode: Handle; VAR saPos: LongInt);
VAR
segInfo: SegmentInfo;
mySize: LongInt;
BEGIN
mySize := codeSize - kCodeHdr; { strip off the header }
{ Get the segment info }
BlockMove(theCode^, @segInfo, SizeOf(SegmentInfo));
{ Move the segment into standalone code, but not code header }
BlockMove(Ptr(ORD(theCode^)+kCodeHdr),
Ptr(ORD(saCode^)+saPos), mySize);
{ We are only going to adjust the segment that the main entry }
{ point is in. That is _always_ segment zero! }
AdjustMainJTable(saCode, saPos, segNum, 0, segInfo.firstProc, segInfo.numJTProcs);
saPos := saPos + mySize;
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.MergeCodeSegments(saCode: Handle; VAR saPos: LongInt);
VAR
theCode: Handle;
theSize: LongInt;
BEGIN
{ merge in CODE 1 first! }
theCode := NIL;
theCode := Get1Resource('CODE', 1);
FailNilResource(theCode);
theSize := SizeResource(theCode);
Merge1Segment(1, theCode, theSize, saCode, saPos);
ReleaseResource(theCode);
ShowNumericalProgress('Code 1 ends at: ', saPos);
{ We only merge CODE 1 for multi-segment stand alone code. }
{ The remaining CODE segments are left as code segments, though }
{ we should consider renaming them.(?) Also, because we leave }
{ them alone, we don't have to adjust the jump table entries for these }
{ segments! (not often that the work is already done for you...) }
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
PROCEDURE TMultiSegSA.BuildStandAlone;
VAR
code0: Handle;
ctordtorJT: Handle;
saCode: Handle;
pos: LongInt;
fi: FailInfo;
PROCEDURE HdlFailure(error: Integer; message: LongInt);
BEGIN
IF (saCode <> NIL) THEN DisposHandle(saCode);
IF (code0 <> NIL) THEN ReleaseResource(code0);
IF (ctordtorJT <> NIL) THEN ReleaseResource(ctordtorJT);
END;
BEGIN
code0 := NIL;
saCode := NIL;
pos := 0;
CatchFailures(fi, HdlFailure);
saCode := AllocateSACode(GetSACodeSize);
code0 := GetCode0;
BuildBSR(code0, saCode, pos);
BuildSegType(fOtherType, saCode, pos);
BuildJumpTable(code0, saCode, pos);
ReleaseResource(code0);
code0 := NIL;
ctordtorJT := NIL;
ctordtorJT := GetCtorDtorJT;
BuildCtorJTable(ctordtorJT, saCode, pos);
BuildDtorJTable(ctordtorJT, saCode, pos);
IF (ctordtorJT <> NIL) THEN { If we found the CtorDtor jumptable }
ReleaseResource(ctordtorJT);
BuildSegTable(saCode, pos);
MergeCodeSegments(saCode, pos);
ShowNumericalProgress('Final size of standalone is: ', pos);
AddOtherCodeSegments(saCode, fOtherType);
SetHandleSize(saCode, pos); { Shorten handle size to actual length used }
AddMainSegment(saCode);
CloseSourceFile;
CloseDestinationFile;
Success(fi);
ShowTextProgress('Done.');
END;
{--------------------------------------------------------------------------------------------------}
{$S TRes}
{ Take a file, extract the various needed CODE resources and massage }
{ them into the single standalone code resource. }
PROCEDURE TMultiSegSA.DoIt;
BEGIN
OpenFiles;
CalcSACodeSize;
BuildStandAlone;
END;
{--------------------------------------------------------------------------------------------------}